home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixScale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  23.4 KB  |  829 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnixScale.c --
  3.  *
  4.  *    This file implements the X specific portion of the scrollbar
  5.  *    widget.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkUnixScale.c 1.5 96/07/31 14:22:29
  13.  */
  14.  
  15. #include "tkScale.h"
  16. #include "tkInt.h"
  17.  
  18. /*
  19.  * Forward declarations for procedures defined later in this file:
  20.  */
  21.  
  22. static void        DisplayHorizontalScale _ANSI_ARGS_((TkScale *scalePtr,
  23.                 Drawable drawable, XRectangle *drawnAreaPtr));
  24. static void        DisplayHorizontalValue _ANSI_ARGS_((TkScale *scalePtr,
  25.                 Drawable drawable, double value, int top));
  26. static void        DisplayVerticalScale _ANSI_ARGS_((TkScale *scalePtr,
  27.                 Drawable drawable, XRectangle *drawnAreaPtr));
  28. static void        DisplayVerticalValue _ANSI_ARGS_((TkScale *scalePtr,
  29.                 Drawable drawable, double value, int rightEdge));
  30.  
  31. /*
  32.  *----------------------------------------------------------------------
  33.  *
  34.  * TkpCreateScale --
  35.  *
  36.  *    Allocate a new TkScale structure.
  37.  *
  38.  * Results:
  39.  *    Returns a newly allocated TkScale structure.
  40.  *
  41.  * Side effects:
  42.  *    None.
  43.  *
  44.  *----------------------------------------------------------------------
  45.  */
  46.  
  47. TkScale *
  48. TkpCreateScale(tkwin)
  49.     Tk_Window tkwin;
  50. {
  51.     return (TkScale *) ckalloc(sizeof(TkScale));
  52. }
  53.  
  54. /*
  55.  *----------------------------------------------------------------------
  56.  *
  57.  * TkpDestroyScale --
  58.  *
  59.  *    Destroy a TkScale structure.
  60.  *
  61.  * Results:
  62.  *    None
  63.  *
  64.  * Side effects:
  65.  *    Memory is freed.
  66.  *
  67.  *----------------------------------------------------------------------
  68.  */
  69.  
  70. void
  71. TkpDestroyScale(scalePtr)
  72.     TkScale *scalePtr;
  73. {
  74.     ckfree((char *) scalePtr);
  75. }
  76.  
  77. /*
  78.  *--------------------------------------------------------------
  79.  *
  80.  * DisplayVerticalScale --
  81.  *
  82.  *    This procedure redraws the contents of a vertical scale
  83.  *    window.  It is invoked as a do-when-idle handler, so it only
  84.  *    runs when there's nothing else for the application to do.
  85.  *
  86.  * Results:
  87.  *    There is no return value.  If only a part of the scale needs
  88.  *    to be redrawn, then drawnAreaPtr is modified to reflect the
  89.  *    area that was actually modified.
  90.  *
  91.  * Side effects:
  92.  *    Information appears on the screen.
  93.  *
  94.  *--------------------------------------------------------------
  95.  */
  96.  
  97. static void
  98. DisplayVerticalScale(scalePtr, drawable, drawnAreaPtr)
  99.     TkScale *scalePtr;            /* Widget record for scale. */
  100.     Drawable drawable;            /* Where to display scale (window
  101.                      * or pixmap). */
  102.     XRectangle *drawnAreaPtr;        /* Initally contains area of window;
  103.                      * if only a part of the scale is
  104.                      * redrawn, gets modified to reflect
  105.                      * the part of the window that was
  106.                      * redrawn. */
  107. {
  108.     Tk_Window tkwin = scalePtr->tkwin;
  109.     int x, y, width, height, shadowWidth;
  110.     double tickValue;
  111.     Tk_3DBorder sliderBorder;
  112.  
  113.     /*
  114.      * Display the information from left to right across the window.
  115.      */
  116.  
  117.     if (!(scalePtr->flags & REDRAW_OTHER)) {
  118.     drawnAreaPtr->x = scalePtr->vertTickRightX;
  119.     drawnAreaPtr->y = scalePtr->inset;
  120.     drawnAreaPtr->width = scalePtr->vertTroughX + scalePtr->width
  121.         + 2*scalePtr->borderWidth - scalePtr->vertTickRightX;
  122.     drawnAreaPtr->height -= 2*scalePtr->inset;
  123.     }
  124.     Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
  125.         drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
  126.         drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
  127.     if (scalePtr->flags & REDRAW_OTHER) {
  128.     /*
  129.      * Display the tick marks.
  130.      */
  131.  
  132.     if (scalePtr->tickInterval != 0) {
  133.         for (tickValue = scalePtr->fromValue; ;
  134.             tickValue += scalePtr->tickInterval) {
  135.         /*
  136.          * The TkRoundToResolution call gets rid of accumulated
  137.          * round-off errors, if any.
  138.          */
  139.  
  140.         tickValue = TkRoundToResolution(scalePtr, tickValue);
  141.         if (scalePtr->toValue >= scalePtr->fromValue) {
  142.             if (tickValue > scalePtr->toValue) {
  143.             break;
  144.             }
  145.         } else {
  146.             if (tickValue < scalePtr->toValue) {
  147.             break;
  148.             }
  149.         }
  150.         DisplayVerticalValue(scalePtr, drawable, tickValue,
  151.             scalePtr->vertTickRightX);
  152.         }
  153.     }
  154.     }
  155.  
  156.     /*
  157.      * Display the value, if it is desired.
  158.      */
  159.  
  160.     if (scalePtr->showValue) {
  161.     DisplayVerticalValue(scalePtr, drawable, scalePtr->value,
  162.         scalePtr->vertValueRightX);
  163.     }
  164.  
  165.     /*
  166.      * Display the trough and the slider.
  167.      */
  168.  
  169.     Tk_Draw3DRectangle(tkwin, drawable,
  170.         scalePtr->bgBorder, scalePtr->vertTroughX, scalePtr->inset,
  171.         scalePtr->width + 2*scalePtr->borderWidth,
  172.         Tk_Height(tkwin) - 2*scalePtr->inset, scalePtr->borderWidth,
  173.         TK_RELIEF_SUNKEN);
  174.     XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
  175.         scalePtr->vertTroughX + scalePtr->borderWidth,
  176.         scalePtr->inset + scalePtr->borderWidth,
  177.         (unsigned) scalePtr->width,
  178.         (unsigned) (Tk_Height(tkwin) - 2*scalePtr->inset
  179.         - 2*scalePtr->borderWidth));
  180.     if (scalePtr->state == tkActiveUid) {
  181.     sliderBorder = scalePtr->activeBorder;
  182.     } else {
  183.     sliderBorder = scalePtr->bgBorder;
  184.     }
  185.     width = scalePtr->width;
  186.     height = scalePtr->sliderLength/2;
  187.     x = scalePtr->vertTroughX + scalePtr->borderWidth;
  188.     y = TkpValueToPixel(scalePtr, scalePtr->value) - height;
  189.     shadowWidth = scalePtr->borderWidth/2;
  190.     if (shadowWidth == 0) {
  191.     shadowWidth = 1;
  192.     }
  193.     Tk_Draw3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
  194.         2*height, shadowWidth, scalePtr->sliderRelief);
  195.     x += shadowWidth;
  196.     y += shadowWidth;
  197.     width -= 2*shadowWidth;
  198.     height -= shadowWidth;
  199.     Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
  200.         height, shadowWidth, scalePtr->sliderRelief);
  201.     Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y+height,
  202.         width, height, shadowWidth, scalePtr->sliderRelief);
  203.  
  204.     /*
  205.      * Draw the label to the right of the scale.
  206.      */
  207.  
  208.     if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
  209.     Tk_FontMetrics fm;
  210.  
  211.     Tk_GetFontMetrics(scalePtr->tkfont, &fm);
  212.     Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
  213.         scalePtr->tkfont, scalePtr->label, scalePtr->labelLength,
  214.         scalePtr->vertLabelX, scalePtr->inset + (3*fm.ascent)/2);
  215.     }
  216. }
  217.  
  218. /*
  219.  *----------------------------------------------------------------------
  220.  *
  221.  * DisplayVerticalValue --
  222.  *
  223.  *    This procedure is called to display values (scale readings)
  224.  *    for vertically-oriented scales.
  225.  *
  226.  * Results:
  227.  *    None.
  228.  *
  229.  * Side effects:
  230.  *    The numerical value corresponding to value is displayed with
  231.  *    its right edge at "rightEdge", and at a vertical position in
  232.  *    the scale that corresponds to "value".
  233.  *
  234.  *----------------------------------------------------------------------
  235.  */
  236.  
  237. static void
  238. DisplayVerticalValue(scalePtr, drawable, value, rightEdge)
  239.     register TkScale *scalePtr;    /* Information about widget in which to
  240.                  * display value. */
  241.     Drawable drawable;        /* Pixmap or window in which to draw
  242.                  * the value. */
  243.     double value;        /* Y-coordinate of number to display,
  244.                  * specified in application coords, not
  245.                  * in pixels (we'll compute pixels). */
  246.     int rightEdge;        /* X-coordinate of right edge of text,
  247.                  * specified in pixels. */
  248. {
  249.     register Tk_Window tkwin = scalePtr->tkwin;
  250.     int y, width, length;
  251.     char valueString[PRINT_CHARS];
  252.     Tk_FontMetrics fm;
  253.  
  254.     Tk_GetFontMetrics(scalePtr->tkfont, &fm);
  255.     y = TkpValueToPixel(scalePtr, value) + fm.ascent/2;
  256.     sprintf(valueString, scalePtr->format, value);
  257.     length = strlen(valueString);
  258.     width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
  259.  
  260.     /*
  261.      * Adjust the y-coordinate if necessary to keep the text entirely
  262.      * inside the window.
  263.      */
  264.  
  265.     if ((y - fm.ascent) < (scalePtr->inset + SPACING)) {
  266.     y = scalePtr->inset + SPACING + fm.ascent;
  267.     }
  268.     if ((y + fm.descent) > (Tk_Height(tkwin) - scalePtr->inset - SPACING)) {
  269.     y = Tk_Height(tkwin) - scalePtr->inset - SPACING - fm.descent;
  270.     }
  271.     Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
  272.         scalePtr->tkfont, valueString, length, rightEdge - width, y);
  273. }
  274.  
  275. /*
  276.  *--------------------------------------------------------------
  277.  *
  278.  * DisplayHorizontalScale --
  279.  *
  280.  *    This procedure redraws the contents of a horizontal scale
  281.  *    window.  It is invoked as a do-when-idle handler, so it only
  282.  *    runs when there's nothing else for the application to do.
  283.  *
  284.  * Results:
  285.  *    There is no return value.  If only a part of the scale needs
  286.  *    to be redrawn, then drawnAreaPtr is modified to reflect the
  287.  *    area that was actually modified.
  288.  *
  289.  * Side effects:
  290.  *    Information appears on the screen.
  291.  *
  292.  *--------------------------------------------------------------
  293.  */
  294.  
  295. static void
  296. DisplayHorizontalScale(scalePtr, drawable, drawnAreaPtr)
  297.     TkScale *scalePtr;            /* Widget record for scale. */
  298.     Drawable drawable;            /* Where to display scale (window
  299.                      * or pixmap). */
  300.     XRectangle *drawnAreaPtr;        /* Initally contains area of window;
  301.                      * if only a part of the scale is
  302.                      * redrawn, gets modified to reflect
  303.                      * the part of the window that was
  304.                      * redrawn. */
  305. {
  306.     register Tk_Window tkwin = scalePtr->tkwin;
  307.     int x, y, width, height, shadowWidth;
  308.     double tickValue;
  309.     Tk_3DBorder sliderBorder;
  310.  
  311.     /*
  312.      * Display the information from bottom to top across the window.
  313.      */
  314.  
  315.     if (!(scalePtr->flags & REDRAW_OTHER)) {
  316.     drawnAreaPtr->x = scalePtr->inset;
  317.     drawnAreaPtr->y = scalePtr->horizValueY;
  318.     drawnAreaPtr->width -= 2*scalePtr->inset;
  319.     drawnAreaPtr->height = scalePtr->horizTroughY + scalePtr->width
  320.         + 2*scalePtr->borderWidth - scalePtr->horizValueY;
  321.     }
  322.     Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
  323.         drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
  324.         drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
  325.     if (scalePtr->flags & REDRAW_OTHER) {
  326.     /*
  327.      * Display the tick marks.
  328.      */
  329.  
  330.     if (scalePtr->tickInterval != 0) {
  331.         for (tickValue = scalePtr->fromValue; ;
  332.             tickValue += scalePtr->tickInterval) {
  333.         /*
  334.          * The TkRoundToResolution call gets rid of accumulated
  335.          * round-off errors, if any.
  336.          */
  337.  
  338.         tickValue = TkRoundToResolution(scalePtr, tickValue);
  339.         if (scalePtr->toValue >= scalePtr->fromValue) {
  340.             if (tickValue > scalePtr->toValue) {
  341.             break;
  342.             }
  343.         } else {
  344.             if (tickValue < scalePtr->toValue) {
  345.             break;
  346.             }
  347.         }
  348.         DisplayHorizontalValue(scalePtr, drawable, tickValue,
  349.             scalePtr->horizTickY);
  350.         }
  351.     }
  352.     }
  353.  
  354.     /*
  355.      * Display the value, if it is desired.
  356.      */
  357.  
  358.     if (scalePtr->showValue) {
  359.     DisplayHorizontalValue(scalePtr, drawable, scalePtr->value,
  360.         scalePtr->horizValueY);
  361.     }
  362.  
  363.     /*
  364.      * Display the trough and the slider.
  365.      */
  366.  
  367.     y = scalePtr->horizTroughY;
  368.     Tk_Draw3DRectangle(tkwin, drawable,
  369.         scalePtr->bgBorder, scalePtr->inset, y,
  370.         Tk_Width(tkwin) - 2*scalePtr->inset,
  371.         scalePtr->width + 2*scalePtr->borderWidth,
  372.         scalePtr->borderWidth, TK_RELIEF_SUNKEN);
  373.     XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
  374.         scalePtr->inset + scalePtr->borderWidth,
  375.         y + scalePtr->borderWidth,
  376.         (unsigned) (Tk_Width(tkwin) - 2*scalePtr->inset
  377.         - 2*scalePtr->borderWidth),
  378.         (unsigned) scalePtr->width);
  379.     if (scalePtr->state == tkActiveUid) {
  380.     sliderBorder = scalePtr->activeBorder;
  381.     } else {
  382.     sliderBorder = scalePtr->bgBorder;
  383.     }
  384.     width = scalePtr->sliderLength/2;
  385.     height = scalePtr->width;
  386.     x = TkpValueToPixel(scalePtr, scalePtr->value) - width;
  387.     y += scalePtr->borderWidth;
  388.     shadowWidth = scalePtr->borderWidth/2;
  389.     if (shadowWidth == 0) {
  390.     shadowWidth = 1;
  391.     }
  392.     Tk_Draw3DRectangle(tkwin, drawable, sliderBorder,
  393.         x, y, 2*width, height, shadowWidth, scalePtr->sliderRelief);
  394.     x += shadowWidth;
  395.     y += shadowWidth;
  396.     width -= shadowWidth;
  397.     height -= 2*shadowWidth;
  398.     Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width, height,
  399.         shadowWidth, scalePtr->sliderRelief);
  400.     Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x+width, y,
  401.         width, height, shadowWidth, scalePtr->sliderRelief);
  402.  
  403.     /*
  404.      * Draw the label at the top of the scale.
  405.      */
  406.  
  407.     if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
  408.     Tk_FontMetrics fm;
  409.  
  410.     Tk_GetFontMetrics(scalePtr->tkfont, &fm);
  411.     Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
  412.         scalePtr->tkfont, scalePtr->label, scalePtr->labelLength,
  413.         scalePtr->inset + fm.ascent/2, scalePtr->horizLabelY + fm.ascent);
  414.     }
  415. }
  416.  
  417. /*
  418.  *----------------------------------------------------------------------
  419.  *
  420.  * DisplayHorizontalValue --
  421.  *
  422.  *    This procedure is called to display values (scale readings)
  423.  *    for horizontally-oriented scales.
  424.  *
  425.  * Results:
  426.  *    None.
  427.  *
  428.  * Side effects:
  429.  *    The numerical value corresponding to value is displayed with
  430.  *    its bottom edge at "bottom", and at a horizontal position in
  431.  *    the scale that corresponds to "value".
  432.  *
  433.  *----------------------------------------------------------------------
  434.  */
  435.  
  436. static void
  437. DisplayHorizontalValue(scalePtr, drawable, value, top)
  438.     register TkScale *scalePtr;    /* Information about widget in which to
  439.                  * display value. */
  440.     Drawable drawable;        /* Pixmap or window in which to draw
  441.                  * the value. */
  442.     double value;        /* X-coordinate of number to display,
  443.                  * specified in application coords, not
  444.                  * in pixels (we'll compute pixels). */
  445.     int top;            /* Y-coordinate of top edge of text,
  446.                  * specified in pixels. */
  447. {
  448.     register Tk_Window tkwin = scalePtr->tkwin;
  449.     int x, y, length, width;
  450.     char valueString[PRINT_CHARS];
  451.     Tk_FontMetrics fm;
  452.  
  453.     x = TkpValueToPixel(scalePtr, value);
  454.     Tk_GetFontMetrics(scalePtr->tkfont, &fm);
  455.     y = top + fm.ascent;
  456.     sprintf(valueString, scalePtr->format, value);
  457.     length = strlen(valueString);
  458.     width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
  459.  
  460.     /*
  461.      * Adjust the x-coordinate if necessary to keep the text entirely
  462.      * inside the window.
  463.      */
  464.  
  465.     x -= (width)/2;
  466.     if (x < (scalePtr->inset + SPACING)) {
  467.     x = scalePtr->inset + SPACING;
  468.     }
  469.     if (x > (Tk_Width(tkwin) - scalePtr->inset)) {
  470.     x = Tk_Width(tkwin) - scalePtr->inset - SPACING - width;
  471.     }
  472.     Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
  473.         scalePtr->tkfont, valueString, length, x, y);
  474. }
  475.  
  476. /*
  477.  *----------------------------------------------------------------------
  478.  *
  479.  * TkpDisplayScale --
  480.  *
  481.  *    This procedure is invoked as an idle handler to redisplay
  482.  *    the contents of a scale widget.
  483.  *
  484.  * Results:
  485.  *    None.
  486.  *
  487.  * Side effects:
  488.  *    The scale gets redisplayed.
  489.  *
  490.  *----------------------------------------------------------------------
  491.  */
  492.  
  493. void
  494. TkpDisplayScale(clientData)
  495.     ClientData clientData;    /* Widget record for scale. */
  496. {
  497.     TkScale *scalePtr = (TkScale *) clientData;
  498.     Tk_Window tkwin = scalePtr->tkwin;
  499.     Tcl_Interp *interp = scalePtr->interp;
  500.     Pixmap pixmap;
  501.     int result;
  502.     char string[PRINT_CHARS];
  503.     XRectangle drawnArea;
  504.  
  505.     if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
  506.     goto done;
  507.     }
  508.  
  509.     /*
  510.      * Invoke the scale's command if needed.
  511.      */
  512.  
  513.     Tcl_Preserve((ClientData) scalePtr);
  514.     Tcl_Preserve((ClientData) interp);
  515.     if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
  516.     sprintf(string, scalePtr->format, scalePtr->value);
  517.     result = Tcl_VarEval(interp, scalePtr->command,    " ", string,
  518.                              (char *) NULL);
  519.     if (result != TCL_OK) {
  520.         Tcl_AddErrorInfo(interp, "\n    (command executed by scale)");
  521.         Tcl_BackgroundError(interp);
  522.     }
  523.     }
  524.     Tcl_Release((ClientData) interp);
  525.     scalePtr->flags &= ~INVOKE_COMMAND;
  526.     if (scalePtr->tkwin == NULL) {
  527.     Tcl_Release((ClientData) scalePtr);
  528.     return;
  529.     }
  530.     Tcl_Release((ClientData) scalePtr);
  531.  
  532.     /*
  533.      * In order to avoid screen flashes, this procedure redraws
  534.      * the scale in a pixmap, then copies the pixmap to the
  535.      * screen in a single operation.  This means that there's no
  536.      * point in time where the on-sreen image has been cleared.
  537.      */
  538.  
  539.     pixmap = Tk_GetPixmap(scalePtr->display, Tk_WindowId(tkwin),
  540.         Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  541.     drawnArea.x = 0;
  542.     drawnArea.y = 0;
  543.     drawnArea.width = Tk_Width(tkwin);
  544.     drawnArea.height = Tk_Height(tkwin);
  545.  
  546.     /*
  547.      * Much of the redisplay is done totally differently for
  548.      * horizontal and vertical scales.  Handle the part that's
  549.      * different.
  550.      */
  551.  
  552.     if (scalePtr->vertical) {
  553.     DisplayVerticalScale(scalePtr, pixmap, &drawnArea);
  554.     } else {
  555.     DisplayHorizontalScale(scalePtr, pixmap, &drawnArea);
  556.     }
  557.  
  558.     /*
  559.      * Now handle the part of redisplay that is the same for
  560.      * horizontal and vertical scales:  border and traversal
  561.      * highlight.
  562.      */
  563.  
  564.     if (scalePtr->flags & REDRAW_OTHER) {
  565.     if (scalePtr->relief != TK_RELIEF_FLAT) {
  566.         Tk_Draw3DRectangle(tkwin, pixmap, scalePtr->bgBorder,
  567.             scalePtr->highlightWidth, scalePtr->highlightWidth,
  568.             Tk_Width(tkwin) - 2*scalePtr->highlightWidth,
  569.             Tk_Height(tkwin) - 2*scalePtr->highlightWidth,
  570.             scalePtr->borderWidth, scalePtr->relief);
  571.     }
  572.     if (scalePtr->highlightWidth != 0) {
  573.         GC gc;
  574.     
  575.         if (scalePtr->flags & GOT_FOCUS) {
  576.         gc = Tk_GCForColor(scalePtr->highlightColorPtr, pixmap);
  577.         } else {
  578.         gc = Tk_GCForColor(scalePtr->highlightBgColorPtr, pixmap);
  579.         }
  580.         Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, pixmap);
  581.     }
  582.     }
  583.  
  584.     /*
  585.      * Copy the information from the off-screen pixmap onto the screen,
  586.      * then delete the pixmap.
  587.      */
  588.  
  589.     XCopyArea(scalePtr->display, pixmap, Tk_WindowId(tkwin),
  590.         scalePtr->copyGC, drawnArea.x, drawnArea.y, drawnArea.width,
  591.         drawnArea.height, drawnArea.x, drawnArea.y);
  592.     Tk_FreePixmap(scalePtr->display, pixmap);
  593.  
  594.     done:
  595.     scalePtr->flags &= ~REDRAW_ALL;
  596. }
  597.  
  598. /*
  599.  *----------------------------------------------------------------------
  600.  *
  601.  * TkpScaleElement --
  602.  *
  603.  *    Determine which part of a scale widget lies under a given
  604.  *    point.
  605.  *
  606.  * Results:
  607.  *    The return value is either TROUGH1, SLIDER, TROUGH2, or
  608.  *    OTHER, depending on which of the scale's active elements
  609.  *    (if any) is under the point at (x,y).
  610.  *
  611.  * Side effects:
  612.  *    None.
  613.  *
  614.  *----------------------------------------------------------------------
  615.  */
  616.  
  617. int
  618. TkpScaleElement(scalePtr, x, y)
  619.     TkScale *scalePtr;        /* Widget record for scale. */
  620.     int x, y;            /* Coordinates within scalePtr's window. */
  621. {
  622.     int sliderFirst;
  623.  
  624.     if (scalePtr->vertical) {
  625.     if ((x < scalePtr->vertTroughX)
  626.         || (x >= (scalePtr->vertTroughX + 2*scalePtr->borderWidth +
  627.         scalePtr->width))) {
  628.         return OTHER;
  629.     }
  630.     if ((y < scalePtr->inset)
  631.         || (y >= (Tk_Height(scalePtr->tkwin) - scalePtr->inset))) {
  632.         return OTHER;
  633.     }
  634.     sliderFirst = TkpValueToPixel(scalePtr, scalePtr->value)
  635.         - scalePtr->sliderLength/2;
  636.     if (y < sliderFirst) {
  637.         return TROUGH1;
  638.     }
  639.     if (y < (sliderFirst+scalePtr->sliderLength)) {
  640.         return SLIDER;
  641.     }
  642.     return TROUGH2;
  643.     }
  644.  
  645.     if ((y < scalePtr->horizTroughY)
  646.         || (y >= (scalePtr->horizTroughY + 2*scalePtr->borderWidth +
  647.         scalePtr->width))) {
  648.     return OTHER;
  649.     }
  650.     if ((x < scalePtr->inset)
  651.         || (x >= (Tk_Width(scalePtr->tkwin) - scalePtr->inset))) {
  652.     return OTHER;
  653.     }
  654.     sliderFirst = TkpValueToPixel(scalePtr, scalePtr->value)
  655.         - scalePtr->sliderLength/2;
  656.     if (x < sliderFirst) {
  657.     return TROUGH1;
  658.     }
  659.     if (x < (sliderFirst+scalePtr->sliderLength)) {
  660.     return SLIDER;
  661.     }
  662.     return TROUGH2;
  663. }
  664.  
  665. /*
  666.  *--------------------------------------------------------------
  667.  *
  668.  * TkpSetScaleValue --
  669.  *
  670.  *    This procedure changes the value of a scale and invokes
  671.  *    a Tcl command to reflect the current position of a scale
  672.  *
  673.  * Results:
  674.  *    None.
  675.  *
  676.  * Side effects:
  677.  *    A Tcl command is invoked, and an additional error-processing
  678.  *    command may also be invoked.  The scale's slider is redrawn.
  679.  *
  680.  *--------------------------------------------------------------
  681.  */
  682.  
  683. void
  684. TkpSetScaleValue(scalePtr, value, setVar, invokeCommand)
  685.     register TkScale *scalePtr;    /* Info about widget. */
  686.     double value;        /* New value for scale.  Gets adjusted
  687.                  * if it's off the scale. */
  688.     int setVar;            /* Non-zero means reflect new value through
  689.                  * to associated variable, if any. */
  690.     int invokeCommand;        /* Non-zero means invoked -command option
  691.                  * to notify of new value, 0 means don't. */
  692. {
  693.     char string[PRINT_CHARS];
  694.  
  695.     value = TkRoundToResolution(scalePtr, value);
  696.     if ((value < scalePtr->fromValue)
  697.         ^ (scalePtr->toValue < scalePtr->fromValue)) {
  698.     value = scalePtr->fromValue;
  699.     }
  700.     if ((value > scalePtr->toValue)
  701.         ^ (scalePtr->toValue < scalePtr->fromValue)) {
  702.     value = scalePtr->toValue;
  703.     }
  704.     if (scalePtr->flags & NEVER_SET) {
  705.     scalePtr->flags &= ~NEVER_SET;
  706.     } else if (scalePtr->value == value) {
  707.     return;
  708.     }
  709.     scalePtr->value = value;
  710.     if (invokeCommand) {
  711.     scalePtr->flags |= INVOKE_COMMAND;
  712.     }
  713.     TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER);
  714.  
  715.     if (setVar && (scalePtr->varName != NULL)) {
  716.     sprintf(string, scalePtr->format, scalePtr->value);
  717.     scalePtr->flags |= SETTING_VAR;
  718.     Tcl_SetVar(scalePtr->interp, scalePtr->varName, string,
  719.            TCL_GLOBAL_ONLY);
  720.     scalePtr->flags &= ~SETTING_VAR;
  721.     }
  722. }
  723.  
  724. /*
  725.  *----------------------------------------------------------------------
  726.  *
  727.  * TkpPixelToValue --
  728.  *
  729.  *    Given a pixel within a scale window, return the scale
  730.  *    reading corresponding to that pixel.
  731.  *
  732.  * Results:
  733.  *    A double-precision scale reading.  If the value is outside
  734.  *    the legal range for the scale then it's rounded to the nearest
  735.  *    end of the scale.
  736.  *
  737.  * Side effects:
  738.  *    None.
  739.  *
  740.  *----------------------------------------------------------------------
  741.  */
  742.  
  743. double
  744. TkpPixelToValue(scalePtr, x, y)
  745.     register TkScale *scalePtr;        /* Information about widget. */
  746.     int x, y;                /* Coordinates of point within
  747.                      * window. */
  748. {
  749.     double value, pixelRange;
  750.  
  751.     if (scalePtr->vertical) {
  752.     pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength
  753.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  754.     value = y;
  755.     } else {
  756.     pixelRange = Tk_Width(scalePtr->tkwin) - scalePtr->sliderLength
  757.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  758.     value = x;
  759.     }
  760.  
  761.     if (pixelRange <= 0) {
  762.     /*
  763.      * Not enough room for the slider to actually slide:  just return
  764.      * the scale's current value.
  765.      */
  766.  
  767.     return scalePtr->value;
  768.     }
  769.     value -= scalePtr->sliderLength/2 + scalePtr->inset
  770.         + scalePtr->borderWidth;
  771.     value /= pixelRange;
  772.     if (value < 0) {
  773.     value = 0;
  774.     }
  775.     if (value > 1) {
  776.     value = 1;
  777.     }
  778.     value = scalePtr->fromValue +
  779.         value * (scalePtr->toValue - scalePtr->fromValue);
  780.     return TkRoundToResolution(scalePtr, value);
  781. }
  782.  
  783. /*
  784.  *----------------------------------------------------------------------
  785.  *
  786.  * TkpValueToPixel --
  787.  *
  788.  *    Given a reading of the scale, return the x-coordinate or
  789.  *    y-coordinate corresponding to that reading, depending on
  790.  *    whether the scale is vertical or horizontal, respectively.
  791.  *
  792.  * Results:
  793.  *    An integer value giving the pixel location corresponding
  794.  *    to reading.  The value is restricted to lie within the
  795.  *    defined range for the scale.
  796.  *
  797.  * Side effects:
  798.  *    None.
  799.  *
  800.  *----------------------------------------------------------------------
  801.  */
  802.  
  803. int
  804. TkpValueToPixel(scalePtr, value)
  805.     register TkScale *scalePtr;        /* Information about widget. */
  806.     double value;            /* Reading of the widget. */
  807. {
  808.     int y, pixelRange;
  809.     double valueRange;
  810.  
  811.     valueRange = scalePtr->toValue - scalePtr->fromValue;
  812.     pixelRange = (scalePtr->vertical ? Tk_Height(scalePtr->tkwin)
  813.         : Tk_Width(scalePtr->tkwin)) - scalePtr->sliderLength
  814.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  815.     if (valueRange == 0) {
  816.     y = 0;
  817.     } else {
  818.     y = (int) ((value - scalePtr->fromValue) * pixelRange
  819.           / valueRange + 0.5);
  820.     if (y < 0) {
  821.         y = 0;
  822.     } else if (y > pixelRange) {
  823.         y = pixelRange;
  824.     }
  825.     }
  826.     y += scalePtr->sliderLength/2 + scalePtr->inset + scalePtr->borderWidth;
  827.     return y;
  828. }
  829.